﻿

#region Using Statements

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
using System.Threading;
using System.ComponentModel;
using System.Reflection;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Design;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

using Freeform;
using FGame = Freeform.Game;
using XGame = Microsoft.Xna.Framework.Game;
using FComponent = Freeform.Component;

#endregion


namespace Freeform
{
    /// <summary>
    /// The viewport class represents a section of the game-screen that a scene can be rendered to.
    /// </summary>
    public class Viewport : Component, IGeometric2D
    {

        #region Members

        /// <summary>
        /// Gets the spritebatch used to render this viewport.
        /// </summary>
        public SpriteBatch SpriteBatch { get; private set; }


        /// <summary>
        /// Gets the world that this viewport is displaying.
        /// </summary>
        public World World { get; private set; }


        /// <summary>
        /// Gets or sets whether this viewport is currently visible.
        /// </summary>
        public Boolean IsVisible { get; set; }


        /// <summary>
        /// Gets the rendertarget for this viewport.
        /// </summary>
        public RenderTarget2D RenderTarget { get; private set; }


        /// <summary>
        /// Gets or sets the depth of this viewport (0 = back, 1 = front.)
        /// </summary>
        public Single Depth { get; set; }


        /// <summary>
        /// Gets or sets the colour overlay of this viewport.
        /// </summary>
        public Color ColourOverlay { get; set; }


        /// <summary>
        /// Gets or sets some text to be rendered to the top left corner of the viewport. (Make sure to define a DebugFont also.)
        /// </summary>
        public String DebugText { get; set; }


        /// <summary>
        /// Gets or sets the font to use to render debugging information.
        /// </summary>
        public SpriteFont DebugFont { get; set; }


        /// <summary>
        /// Gets or sets the colour of the debug text.
        /// </summary>
        public Color DebugColour { get; set; }


        /// <summary>
        /// Gets or sets the position of the top left corner of the viewport on the screen. ((0,0) TopLeft, (1,1) BottomRight)
        /// </summary>
        public Vector2 Position { get; set; }


        /// <summary>
        /// Gets or sets the orientation of the viewport on the screen.
        /// </summary>
        public Single Orientation { get; set; }


        /// <summary>
        /// Gets or sets the size of the viewport on the screen. ((1,1) ---> Size of entire screen.)
        /// </summary>
        public Vector2 Size { get; set; }


        /// <summary>
        /// Sets the sorting mode to be used by this viewport when rendering Actors.
        /// </summary>
        public SpriteSortMode SpriteSorting { get; set; }


        /// <summary>
        /// Gets whether the mouse is over this viewport.
        /// </summary>
        public virtual Boolean IsMouseOver
        {
            get
            {
                Vector2 MouseLoc = new Vector2(Mouse.GetState().X, Mouse.GetState().Y);
                Vector2 Resolution = new Vector2(Game.GraphicsDevice.Viewport.Width,
                    Game.GraphicsDevice.Viewport.Height);
                Vector2 MouseFrac = MouseLoc / Resolution;

                if (MouseFrac.X > Position.X && MouseFrac.Y > Position.Y &&
                    MouseFrac.X < Position.X + Size.X &&
                    MouseFrac.Y < Position.Y + Size.Y)
                    return true;
                return false;
            }
        }


        /// <summary>
        /// Gets the position of the mouse in Viewport proportions between Vector2.Zero (TopLeft of Viewport) and Vector2.One (BottomRight of Viewport)
        /// </summary>
        public virtual Vector2 MouseLocation_View
        {
            get
            {
                Vector2 MouseLoc = new Vector2(Mouse.GetState().X, Mouse.GetState().Y);
                Vector2 Resolution = new Vector2(Game.GraphicsDevice.Viewport.Width,
                    Game.GraphicsDevice.Viewport.Height);
                return (MouseLoc / Resolution - Position) / Size;
            }
        }

        #endregion


        #region Init

        /// <summary>
        /// Creates a new generic viewport.
        /// </summary>
        /// <param name="World">The world that this viewport looks at.</param>
        public Viewport(World World)
            : base(World.ComponentList)
        {
            this.World = World;
            IsVisible = true;
            Depth = 0.5f;
            ColourOverlay = Color.White;
            Position = Vector2.Zero;
            Size = Vector2.One;
            RenderTarget = new RenderTarget2D(
                Game.GraphicsDevice, 
                Game.GraphicsDevice.Viewport.Width,
                Game.GraphicsDevice.Viewport.Height,
                false, SurfaceFormat.Color, DepthFormat.Depth24Stencil8, 0, RenderTargetUsage.DiscardContents);
            SpriteBatch = new SpriteBatch(Game.GraphicsDevice);
            SpriteSorting = SpriteSortMode.BackToFront;
            Game.Viewports.Add(this);
            World.Viewports.Add(this);
        }

        #endregion


        #region Update


        #endregion


        #region Draw

        /// <summary>
        /// Allows the viewport to draw itself.
        /// </summary>
        /// <param name="Time">Provides a snapshot of timing values.</param>
        public virtual void Draw(GameTime Time)
        {
            // Render to the rendertarget for this viewport.
            Game.SetRenderTarget(RenderTarget);

            // Clear to background colour.
            Game.GraphicsDevice.Clear(World.BackgroundColour);
        }

        #endregion


        #region Dispose

        /// <summary>
        /// Disposes this viewport and removes it from the game.
        /// </summary>
        protected override void OnDispose()
        {
            base.OnDispose();

            // Remove references from parents.
            Game.Viewports.Remove(this);
            World.Viewports.Remove(this);

            // Dispose rendertarget.
            RenderTarget.Dispose();
        }

        #endregion

    }
}